local EffectEmitter = import(".EffectEmitter")
local Armature = require("app.public.avatar.Armature")
local AvatarFactory = require("app.public.avatar.AvatarFactory")
local SpriteFrameCache =  cc.SpriteFrameCache:getInstance()

local EffectFactory = class("EffectFactory",function() return cc.Layer:create() end)

function EffectFactory:ctor()
    self.idBuilder = 0
end

function EffectFactory:createEffectDisplayNode(resType, resName, releaser, armatureObjectConfig)
    if resType == 1 then
        local sprite = display.newSprite("armatures/effect/"..resName)
        if sprite then
            sprite:setBlendFunc({src = gl.SRC_ALPHA, dst = gl.ONE})
        end
        return sprite
    elseif resType == 2 then
    elseif resType == 3 then
        local armature = Armature.create(
            {
                path = "armatures/".. armatureObjectConfig:getDir(),
                armatureName = armatureObjectConfig:getArmatureName(),
                animationName = "",
            })
        if armature then
            armature:setScaleX(-releaser.dir)
            armature:setMotionStreakOffset(-20,0)
            return armature
        end
    elseif resType == 4 then
    elseif resType == 5 then
        local node
        if iskindof(releaser,"Hero") then
            node = AvatarFactory.createHero(releaser.createParams)
        elseif iskindof(releaser,"Creature") then
            node = AvatarFactory.createNpcOrPartnersByParams(releaser.createParams, true)
        end
        if node then
            node:setScaleX(releaser.originScaleX)
            node:setScaleY(releaser.originScaleY)
        end
        return node
    end
    return nil
end

function EffectFactory:getBindingNodeAndBoneFrom(place, param, releaser, target)
    local bindtype
    if place == "field-center" then
        bindtype = 7
    elseif place == "caster-pos" then
        bindtype = 1
    elseif place == "victim-pos" then
        bindtype = 2
    elseif place == "caster-bone" then
        bindtype = 3
    elseif place == "victim-bone" then
        bindtype = 4
    elseif place == "target-pos" then
        bindtype = 5
    else
        printError("unknown place!!!",place)
    end
    local bone = param
    local bindnode = nil

    if bindtype == 1 or bindtype == 3 or bindtype==5 then
        bindnode = releaser
    elseif bindtype == 2 or bindtype == 4 or bindtype == 6 then
        bindnode = target
    else 
        bindnode = nil
    end
    return bindnode,bone,bindtype
end

function EffectFactory:createEffect(releaser, target, targetPoint, config, armatureObjectConfig)
	local effectResType = 3
    local displayNode = self:createEffectDisplayNode(effectResType, nil, releaser, armatureObjectConfig)
    local moveAni = armatureObjectConfig:getAnimation()
    if not displayNode then 
        printError("EffectFactory:createEffect objectId:"..config:getObjectId())
        displayNode = display.newTTFLabel({
            text = "projectile objectId:"..config:getObjectId().." missing",
            size = 22,
            color = display.COLOR_WHITE,
            align = cc.TEXT_ALIGNMENT_CENTER,
            valign = cc.VERTICAL_TEXT_ALIGNMENT_CENTER})
    end

    local fromPlace = config:getFromPlace()
    local fromParam = config:getFromParam()
    local toPlace = config:getToPlace()
    local toParam = config:getToParam()

    local fromNode ,fromBone, fromBindtype = self:getBindingNodeAndBoneFrom(fromPlace,fromParam, releaser, target)
    local toNode ,toBone, toBindtype = self:getBindingNodeAndBoneFrom(toPlace,toParam, releaser, target)

    local bindType = config:getBindType()
	local zOrder = config:getZOrder() 
	local effectSize = config:getEffectSize()
    local effectMovement = tonumber(config:getEffectMovement())
    local curvedFixedIndex = tonumber(config:getCurvedFixedIndex())
    local curvedRandomIndex = tonumber(config:getCurvedRandomIndex())

    self.idBuilder = self.idBuilder + 1
    local params = {
        id = self.idBuilder,
        relativeNode = self, --坐标相对于此战场层
        displayNode = displayNode,
        targetPoint = targetPoint,
        fromNode = fromNode,
        fromBone = fromBone,
        fromBindtype = fromBindtype,
        toNode = toNode,
        toBone = toBone,
        toBindtype=toBindtype,
        moveAni = moveAni,
        speed = 0,
        moveDuration = 0,
        isCurve = (effectMovement==2),
        curvedFixedIndex = curvedFixedIndex,
        curvedRandomIndex = curvedRandomIndex,
        autoHeadon = config:getHeadon() == 1,

        fromPlace = fromPlace,
        fromParam = fromParam,
        toPlace = toPlace,
        toParam = toParam,
    }
    local emitter = EffectEmitter.create(params)

    if bindType == 1 and releaser then
        releaser:addChild(emitter)
    elseif bindType == 2 and target then
        target:addChild(emitter)
    else
        -- zOrder为1前层   为2后层
        if zOrder == 1 then
            self:addChild(emitter)
        else
            self.backLayer:addChild(emitter)
        end
    end

    --如果不是自己的弹道，需要透明70%
    if not releaser:isSelf() then
        emitter:setCascadeOpacityEnabled(true)
        emitter:setOpacity(Constant.BattleOtherEntityEffectOpacity)
    end

    if zOrder ~= 1 then
        emitter:setLocalZOrder(-1)
    end

    if effectResType ~= 5 then
        local effectSize = effectSize*0.01
        local scale = releaser:getScale()*releaser:getEffectScale()*effectSize
        emitter:setScale(scale)
    end

    return emitter
end

function EffectFactory:createLinkerEffect(index)
    if not index and not tonumber(index) then
        return nil
    end

    if Res.LinkerEffectConfig[index] == nil then
        --如果为空就取第一个
        index = 1
    end
    local params = Res.LinkerEffectConfig[index]

    if params.isHook then
        return EffectFactory:createHookEffect(params)
    elseif params.isScalingHook then
        return EffectFactory:createScalingHookEffect(params)
    end

    SpriteFrameCache:addSpriteFrames(params.dir..params.plist)

    local linker = custom.LinkEffect:create()
    
    local time = Constant.BattleLineAnimDelayPerUnit
    local line = custom.LineEffect:create()

    local function runLineActionFunc()
        line:stopAllActions()
        local animation = cc.Animation:create()
        local maxFrame = params.lineMaxFrame
        local lineName = params.lineName or "line"
        for i=1,maxFrame,1 do
            local frame = SpriteFrameCache:getSpriteFrame(string.format(params.dir..lineName.."%04d.png",i))
            if frame then
                animation:addSpriteFrame(frame)
            end
        end
        
        animation:setDelayPerUnit(time)
        animation:setRestoreOriginalFrame(true)
        animation:setLoops(9999)
        
        local action = cc.Animate:create(animation)
        line:runAction(action)
    end
    
    runLineActionFunc()
    line:setBlendFunc({src = gl.SRC_ALPHA, dst = gl.ONE})
    
    local animation
    local maxFrame
    if params.hasNode then
        local tail = cc.Sprite:create()
        animation = cc.Animation:create()
        maxFrame = params.pointMaxFrame
        for i=1,maxFrame,1 do
            local frame = SpriteFrameCache:getSpriteFrame(string.format(params.dir.."point%04d.png", i))
            if frame then
                animation:addSpriteFrame(frame)
            end
        end
        animation:setDelayPerUnit(time)
        animation:setRestoreOriginalFrame(true)
        animation:setLoops(9999)
        local action = cc.Animate:create(animation)
        tail:runAction(action)
        tail:setAnchorPoint(0.6, 0.5)
        tail:setBlendFunc({src = gl.SRC_ALPHA, dst = gl.ONE})
        tail:setScale(params.scale)
        
        local head = cc.Sprite:create()
        head:setFlippedY(true)
        head:runAction(action:clone())
        head:setAnchorPoint(0.6, 0.5)
        head:setBlendFunc({src = gl.SRC_ALPHA, dst = gl.ONE})
        head:setScale(params.scale)

        linker:setEndNode(tail)
        linker:setStartNode(head)
    end
    
    linker:setLineEffect(line)
    return linker,runLineActionFunc
end

function EffectFactory:createHookEffect(params)
    local lineDir = params.lineDir or "effects/hook/line.png"
    local hookDir = params.hookDir or "effects/hook/hook.png"
    local scale = params.scale or 1.0

    local linker = custom.LinkEffect:create()

    local line = custom.LineEffect:create(lineDir,1)
    local hook = cc.Sprite:create(hookDir)
    if params.hookAnchor then
        hook:setAnchorPoint(params.hookAnchor.x, params.hookAnchor.y)
    else
        hook:setAnchorPoint(0, 0)
    end
    hook:setScale(scale)
    linker:setLineEffect(line)
    linker:setEndNode(hook)
    return linker
end

function EffectFactory:createScalingHookEffect(params)
    local lineDir = params.lineDir or "effects/hook/line.png"
    local hookDir = params.hookDir or "effects/hook/hook.png"
    local scale = params.scale or 1.0

    local linker = custom.LinkEffect:create()

    local line = custom.LineEffect:create(lineDir,0)
    local hook = cc.Sprite:create(hookDir)
    if params.hookAnchor then
        hook:setAnchorPoint(params.hookAnchor.x, params.hookAnchor.y)
    else
        hook:setAnchorPoint(0, 0)
    end
    hook:setScale(scale)
    linker:setLineEffect(line)
    linker:setEndNode(hook)
    return linker
end

return EffectFactory